package com.jochen.core.screen;

import com.badlogic.gdx.*
import com.badlogic.gdx.Screen
import com.jochen.core.world.GdxGame
import com.badlogic.gdx.InputMultiplexer
import com.badlogic.gdx.InputProcessor
import com.jochen.core.tools.*
import kotlin.reflect.KClass
import com.jochen.core.screen.transitions.*
import kotlin.math.roundToInt

class ScreenManager(private val game:GdxGame): Screen{

    companion object{
        const val SCREEN_MANAGER = "ScreenManager"
    }
    
    private val allScreens = mutableMapOf<KClass<out BaseScreen>,BaseScreen>()
    private val allTransitions= mutableMapOf<KClass<out Transition>,Transition>()
    
    private var curScreen: BaseScreen? = null
    private var nextScreen: BaseScreen? = null
    
    val imp: InputMultiplexer = InputMultiplexer()
    private var isTransitionFinished: Boolean = true
    private val defaultTransition: Transition = DefaultTransition()
    private var transition: Transition = defaultTransition
    
    fun setScreen(type: KClass<out BaseScreen>) {
        allScreens[type]?.let{ newScreen ->
            this.curScreen?.hide()
            this.curScreen = newScreen.apply{  show()  }
        }
    }
    
    fun setScreen(type: KClass<out BaseScreen>,transitionType: KClass<out Transition>){
        this.curScreen?.takeIf{ isTransitionFinished }?.let{ _ ->
            allScreens[type]?.let{ newScreen ->
                isTransitionFinished = false
                transition = allTransitions[transitionType]?:defaultTransition
                transition.onStart()
                nextScreen = newScreen.apply{ show() }
            }
        }
    }
    
    fun updateTransition(delta: Float) {
        if(isTransitionFinished) return
        
        transition.update(delta);
        if(transition.isFinished) {
            curScreen?.hide();
            curScreen = nextScreen;
            curScreen?.resume()
            isTransitionFinished = true;
            nextScreen = null;
            transition = defaultTransition
        }
    }
    
    fun destroyScreen(type: KClass<out BaseScreen>) {
        if (isTransitionFinished) {
            allScreens.remove(type)?.dispose()
        }
    }
    
    fun addScreen(screen: BaseScreen){
        Gdx.app.log(SCREEN_MANAGER, "添加屏幕: ${screen::class.simpleName ?: "Anonymous"}")
        allScreens[screen::class] = screen
    } 
    fun addTransitions(ts: Transition){
        Gdx.app.log(SCREEN_MANAGER, "添加过渡: ${ts::class.simpleName ?: "Anonymous"}")
        allTransitions[ts::class] = ts
    } 
    
    fun getTransitions(type: KClass<out Transition>): Transition? = allTransitions[type]
    
    fun addProcessor(ps: InputProcessor){
        imp.addProcessor(ps) 
    }
    
    fun removeProcessor(ps: InputProcessor){
        imp.removeProcessor(ps)
    }
    
    override fun render(delta: Float){
        updateTransition(delta)
        if(isTransitionFinished){
            curScreen?.render(delta)
        }else{
            curScreen?.let{ form ->
                nextScreen?.let{ to ->
                    transition.render(delta,form,to)
                }
            }
        }
    }
    
    override fun show(){
        Gdx.input.inputProcessor = imp
    }
    
    override fun hide(){
        Gdx.input.inputProcessor = null
    }
    
    override fun resize(width: Int, height: Int) {
        listOfNotNull(curScreen, nextScreen).forEach { it.resize(width, height) }
    }
    
    override fun pause(){
        curScreen?.pause()
    }
    
    override fun resume(){
        curScreen?.resume()
    }
   
   override fun dispose() {
       curScreen?.hide()
       nextScreen?.hide()?.also { isTransitionFinished = true }
       allScreens.values.toList().forEach { it.dispose() }
       allTransitions.values.toList().forEach { it.dispose() }
   }
}